Array = Array or {}

function Array.binarySearch(arr, v, index, count, cmpFunc)
end

---@param arrLen number|_nil 为nil时使用#arr获取长度
---@return number 清除后的长度
function Array.clear(arr, index, count, arrLen)
    if nil == arr then return 0 end
    --assert("number" == type(index), "index not number: " .. type(index))
    --assert("number" == type(count), "count not number: " .. type(count))
    
    if nil == index then index = 1 end
    if nil == arrLen then arrLen = #arr end
    if nil == count then count = arrLen - index + 1 end

    assert(index >= 1 and index <= arrLen, "out of range: " .. index)
    
    local index2 = index + count
    if index2 > arrLen then --删除尾部的n个元素
        for i=index,arrLen do
            arr[i] = nil
        end
        arrLen = index - 1
    else --删除中间或开头的n个元素
        local j = index
        for i=index2,arrLen do --尾部的元素往前填充
            arr[j] = arr[i]
            j = j + 1
        end
        for i=j,arrLen do
            arr[i] = nil
        end
        arrLen = arrLen - count
    end
    return arrLen
end

function Array.copy(srcArr, srcIndex, dstArr, dstIndex, count, srcArrLen, dstArrLen)
    if nil == srcIndex then srcIndex = 1 end
    if nil == srcArrLen then srcArrLen = #srcArr end
    if nil == count then count = srcArrLen - index + 1 end
    
    local srcEndIndex = srcIndex + count - 1
    assert(srcIndex >= 1 and srcEndIndex <= srcArrLen, "src out of range: " .. srcArrLen)
    
    if nil == dstArrLen then dstArrLen = #dstArr end
    
    assert(dstIndex >= 1 and dstIndex - 1 <= dstArrLen, "dst out of range: " .. dstArrLen)
    
    local j = 0
    for i=srcIndex,srcEndIndex do
        dstArr[dstIndex+j] = srcArr[i]
        j = j + 1
    end
end

function Array.exists(arr, matchFunc, arrLen)
    if nil == arr then return false end
    
    if nil == arrLen then arrLen = #arr end
    
    for i=1,arrLen do
        local item = arr[i]
        if matchFunc(item) then
            return true
        end
    end
    return false
end

function Array.find(arr, matchFunc, arrLen)
    if nil == arr then return nil end
    
    if nil == arrLen then arrLen = #arr end
    
    for i=1,arrLen do
        local item = arr[i]
        if matchFunc(item) then
            return item
        end
    end
    return nil
end

function Array.findLast(arr, matchFunc, arrLen)
    if nil == arr then return nil end
    
    if nil == arrLen then arrLen = #arr end
    
    for i=arrLen,1,-1 do
        local item = arr[i]
        if matchFunc(item) then
            return item
        end
    end
    return nil
end

function Array.findAll(arr, matchFunc, arrLen)
    if nil == arr then return nil end
    
    if nil == arrLen then arrLen = #arr end
    
    local ret = {}
    for i=1,arrLen do
        local item = arr[i]
        if matchFunc(item) then
            table.insert(ret, item)
        end
    end
    return ret
end

function Array.findIndex(arr, matchFunc, index, count, arrLen)
    if nil == arr then return -1 end
    
    if nil == index then index = 1 end
    if nil == arrLen then arrLen = #arr end
    if nil == count then count = arrLen - index + 1 end
    
    local endIndex = index + count - 1
    assert(index >= 1 and endIndex <= arrLen, "out of range: " .. index .. ", " .. endIndex)
    
    for i=index,endIndex do
        local item = arr[i]
        if matchFunc(item) then
            return i
        end
    end
    return -1
end

function Array.findLastIndex(arr, matchFunc, index, count, arrLen)
    if nil == arr then return -1 end
    
    if nil == index then index = 1 end
    if nil == arrLen then arrLen = #arr end
    if nil == count then count = arrLen - index + 1 end
    
    local endIndex = index + count - 1
    assert(index >= 1 and endIndex <= arrLen, "out of range: " .. index .. ", " .. endIndex)
    
    for i=endIndex,index,-1 do
        local item = arr[i]
        if matchFunc(item) then
            return i
        end
    end
    return -1
end

function Array.indexOf(arr, v, index, count, arrLen)
    if nil == arr then return -1 end
    
    if nil == index then index = 1 end
    if nil == arrLen then arrLen = #arr end
    if nil == count then count = arrLen - index + 1 end
    
    local endIndex = index + count - 1
    assert(index >= 1 and endIndex <= arrLen, "out of range: " .. index .. ", " .. endIndex)
    
    for i=index,endIndex do
        local item = arr[i]
        if v == item then
            return i
        end
    end
    return -1
end

function Array.lastIndexOf(arr, v, index, count, arrLen)
    if nil == arr then return -1 end
    
    if nil == index then index = 1 end
    if nil == arrLen then arrLen = #arr end
    if nil == count then count = arrLen - index + 1 end
    
    local endIndex = index + count - 1
    assert(index >= 1 and endIndex <= arrLen, "out of range: " .. index .. ", " .. endIndex)
    
    for i=endIndex,index,-1 do
        local item = arr[i]
        if v == item then
            return i
        end
    end
    return -1
end

function Array.print(arr, index, count)
    if nil == index then index = 1 end
    if nil == count then count = #arr end
    
    local strTb = {}
    for i=index,index+count-1 do
        local item = arr[i]
        if nil == item then 
            table.insert(strTb, "nil")
        else
            table.insert(strTb, tostring(item))
        end
    end
    print(table.concat(strTb, ", "))
end

function Array:__tostring()
    return ""
end

function Array:__index(k)
    error("invalid access: " .. k)
end

function Array:__newindex(k, v)
    error("invalid operation: " .. k)
end
setmetatable(Array, Array)


local function Test1()
    local arr = {1, 2, 3}
    Array.clear(arr, 1, 2)
    assert(3 == arr[1])
    assert(nil == arr[2])
    --Array.print(arr)
    
    arr = {1, 2, 3, 4, 5}
    local dst = {"a"}
    Array.copy(arr, 2, dst, 2, 3)
    assert("a" == dst[1])
    assert(2 == dst[2])
    assert(3 == dst[3])
    assert(4 == dst[4])
    assert(nil == dst[5])
    
    local match0Func = function(item)
        return 0 == item
    end
    local match2Func = function(item)
        return 2 == item
    end
    
    assert(Array.exists(arr, match2Func), "exists error")
    
    assert(false == Array.exists(arr, match0Func), "exists error")
    
    assert(-1 == Array.findIndex(arr, match0Func), "findIndex error")
    assert(2 == Array.findIndex(arr, match2Func), "findIndex error")
    assert(-1 == Array.findIndex(arr, match2Func, 3), "findIndex error")
    assert(-1 == Array.findIndex(arr, match2Func, 1, 1), "findIndex error")
    assert(2 == Array.findIndex(arr, match2Func, 2, 1), "findIndex error")
    
    arr = {1, 2, 3, 4, 5, 2, 1}
    assert(6 == Array.findLastIndex(arr, match2Func), "findLastIndex error")
    assert(-1 == Array.findLastIndex(arr, match2Func, 3, 3), "findLastIndex error")
    assert(2 == Array.findLastIndex(arr, match2Func, 1, 3), "findLastIndex error")
    
    assert(2 == Array.indexOf(arr, 2), "indexOf error")
    assert(-1 == Array.indexOf(arr, 3, 4), "indexOf error")
    assert(-1 == Array.indexOf(arr, 4, 1, 3), "indexOf error")
    
    assert(6 == Array.lastIndexOf(arr, 2), "indexOf error")
    assert(2 == Array.lastIndexOf(arr, 2, 1, 3), "indexOf error")
    assert(-1 == Array.lastIndexOf(arr, 2, 3, 3), "indexOf error")
end

Test1()


